package com.passion.solr.service.impl;

import com.google.common.collect.Maps;
import com.passion.common.exception.MyException;
import com.passion.search.annotation.SolrIndex;
import com.passion.solr.enums.SolrEnums;
import com.passion.solr.frm.SchemaFieldOperateFrm;
import com.passion.solr.service.SolrManageService;
import com.passion.solr.util.SolrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 类描述：solr管理服务实现类
 *
 * @author ZhuYin
 * @since 2024年09月23日
 */
@Slf4j
@Service
public class SolrManageServiceImpl implements SolrManageService {

    /**
     * 方法说明：向solr的schema配置汇中添加或删除字段
     *
     * @param frm 字段操作参数对象
     * @return Map 返回：{"result": true, "message": ""} 或 {"result": false, "message": "xxx"}
     * @author ZhuYin
     * @since 2024年09月23日
     */
    @Override
    public Map<String, Object> operateField(SchemaFieldOperateFrm frm) {
        SolrEnums.SchemaFieldOperateType[] values = SolrEnums.SchemaFieldOperateType.values();
        if (Arrays.stream(values).noneMatch(x -> x.getCode().equals(frm.getOperateType()))) {
            throw new MyException("操作类型有误");
        }
        if (StringUtils.isBlank(frm.getName())) {
            throw new MyException("字段名称不能为空");
        }
        return SolrUtil.operateField(frm);
    }

    /**
     * 方法说明：初始化 coreName 这个core的字段
     *
     * @return Map 返回：{"result": true, "message": ""} 或 {"result": false, "message": "xxx"}
     * @author ZhuYin
     * @since 2024年09月23日
     */
    @Override
    public Map<String, Object> initCoreFields(String coreName) throws Exception {
        Map<String, Object> retMap = Maps.newHashMap();
        List<String> totalFields = Lists.newArrayList();
        List<String> successFields = Lists.newArrayList();
        List<String> failedFields = Lists.newArrayList();
        StringBuilder sb = new StringBuilder();
        Class<?> clazz = SolrEnums.SolrCore.getClassByCoreName(coreName);
        if (clazz == null) {
            throw new MyException(coreName + "对应的实体类不存在");
        }
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            // 如果solr字段与数据库字段保持一致的话，可以使用这种方式: String fieldName = StrUtil.humpToUnderline(field.getName())
            String fieldName = field.getName();
            if ("id".equals(fieldName) || "serialVersionUID".equals(fieldName)) {
                // id 和 序列化字段不创建索引
                continue;
            }
            SolrIndex annotation = field.getAnnotation(SolrIndex.class);
            if (annotation != null) {
                log.info("加了@SolrIndex注解的字段：{}", fieldName);
                String solrFieldName = annotation.name();
                totalFields.add(solrFieldName);
                String solrType = annotation.type();
                boolean indexed = annotation.indexed();
                boolean stored = annotation.stored();
                boolean multiValued = annotation.multiValued();
                try {
                    SchemaFieldOperateFrm frm = new SchemaFieldOperateFrm();
                    frm.setOperateType(SolrEnums.SchemaFieldOperateType.addField.getCode());
                    frm.setCoreName(coreName);
                    frm.setName(solrFieldName);
                    frm.setStored(stored);
                    frm.setIndexed(indexed);
                    frm.setType(solrType);
                    frm.setMultiValued(multiValued);
                    Map<String, Object> map = SolrUtil.operateField(frm);
                    if ((Boolean) map.get("result")) {
                        successFields.add(solrFieldName);
                    } else {
                        failedFields.add(solrFieldName);
                        sb.append(map.get("message"));
                    }
                } catch (Exception e) {
                    failedFields.add(solrFieldName);
                    sb.append(e.getMessage());
                    log.error("初始化Solr字段[{}]异常：", fieldName, e);
                }
            }
        }
        logInfo("新增", coreName, totalFields, successFields, failedFields, sb.toString());
        retMap.put("result", failedFields.isEmpty());
        retMap.put("message", sb.toString());
        return retMap;
    }

    /**
     * 方法说明：删除指定core的字段
     * core字段太多的话，此接口删除太费劲，可直接去修改solr的配置文件
     * @param coreName core名称
     * @return Map 返回：{"result": true, "message": ""} 或 {"result": false, "message": "xxx"}
     * @author ZhuYin
     * @since 2024年09月23日
     */
    @Override
    public Map<String, Object> deleteCoreFields(String coreName) {
        Map<String, Object> retMap = Maps.newHashMap();
        List<String> totalFields = Lists.newArrayList();
        List<String> successFields = Lists.newArrayList();
        List<String> failedFields = Lists.newArrayList();
        StringBuilder sb = new StringBuilder();
        Class<?> clazz = SolrEnums.SolrCore.getClassByCoreName(coreName);
        if (clazz == null) {
            throw new MyException(coreName + "对应的实体类不存在");
        }
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            // 如果solr字段与数据库字段保持一致的话，可以使用这种方式: String fieldName = StrUtil.humpToUnderline(field.getName())
            String fieldName = field.getName();
            if ("id".equals(fieldName) || "serialVersionUID".equals(fieldName)) {
                // id 和 序列化字段不创建索引
                continue;
            }
            SolrIndex annotation = field.getAnnotation(SolrIndex.class);
            if (annotation != null) {
                log.info("加了@Field注解的字段：{}", fieldName);
                String solrFieldName = annotation.name();
                totalFields.add(solrFieldName);
                try {
                    SchemaFieldOperateFrm frm = new SchemaFieldOperateFrm();
                    frm.setCoreName(coreName);
                    frm.setName(solrFieldName);
                    frm.setOperateType(SolrEnums.SchemaFieldOperateType.deleteField.getCode());
                    Map<String, Object> result = SolrUtil.operateField(frm);
                    if (!(Boolean) result.get("result")) {
                        failedFields.add(solrFieldName);
                        sb.append(result.get("message"));
                    } else {
                        successFields.add(solrFieldName);
                    }
                } catch (Exception e) {
                    failedFields.add(solrFieldName);
                    sb.append(e.getMessage());
                    log.error("删除Solr字段[{}]异常：", solrFieldName, e);
                }
            }
        }
        logInfo("删除", coreName, totalFields, successFields, failedFields, sb.toString());
        retMap.put("result", failedFields.isEmpty());
        retMap.put("message", sb.toString());
        return retMap;
    }

    private static void logInfo(String operation, String coreName, List<String> totalFieldsList, List<String> successFieldsList, List<String> failedFieldsList, String errorMsg) {
        StringBuilder sb = new StringBuilder();
        sb.append("\n||========================{}solr字段定义============================");
        sb.append("\n||       CoreName: ").append(coreName);
        sb.append("\n||   Total Fields: ").append(totalFieldsList.size());
        sb.append("\n||   Total detail: ").append(totalFieldsList);
        sb.append("\n|| Succeed Fields: ").append(successFieldsList.size());
        sb.append("\n|| Succeed detail: ").append(successFieldsList);
        sb.append("\n||  Failed Fields: ").append(failedFieldsList.size());
        sb.append("\n||  Failed detail: ").append(failedFieldsList);
        sb.append("\n|| Failed Message: \n\t\t").append(errorMsg.replace("\n",  "\n\t\t"));
        sb.append("\n||================================================================");
        log.info(sb.toString(), operation);
    }

}
